---
title: Push notifications setup
sidebar_title: Setup
description: Learn how to setup push notifications, get credentials for development and production, and test sending push notifications.
---

import { Collapsible } from '~/ui/components/Collapsible';
import { ContentSpotlight } from '~/ui/components/ContentSpotlight';
import { Terminal } from '~/ui/components/Snippet';
import { Step } from '~/ui/components/Step';
import { Tab, Tabs } from '~/ui/components/Tabs';

To utilize Expo's push notification service, you must configure your app by installing a set of libraries, implementing functions to handle notifications, and setting up credentials for Android and iOS. Once you have completed the steps mentioned in this guide, you'll be able to test sending and receiving notifications on a device.

To get the client-side ready for push notifications, the following things are required:

- The user's permission to send them push notifications.
- The user's [`ExpoPushToken`](/versions/latest/sdk/notifications/#expopushtoken).

<br />
<Collapsible summary="Do you want to use FCMv1/APNs directly, instead of through the Expo push notification service?">

You may need finer-grained control over your notifications, so communicating directly with FCM and APNs may be necessary. The Expo platform does not lock you into using Expo's application services, and the `expo-notifications` API is push-service agnostic. Learn how to ["Send notifications with FCMv1 and APNs"](/push-notifications/sending-notifications-custom/).

</Collapsible>

## Prerequisites

The following steps described in this guide use [EAS Build](/build/introduction/). However, you can use the `expo-notifications` library without EAS Build by building [your project locally](/workflow/customizing/).

<Step label="1">

## Install libraries

Run the following command to install the `expo-notifications`, `expo-device` and `expo-constants` libraries:

<Terminal cmd={['$ npx expo install expo-notifications expo-device expo-constants']} />

- [`expo-notifications`](/versions/latest/sdk/notifications) library is used to request a user's permission and to fetch the `ExpoPushToken`. It is not supported on an Android Emulator or an iOS Simulator.
- [`expo-device`](/versions/latest/sdk/device) is used to check whether the app is running on a physical device.
- [`expo-constants`](/versions/latest/sdk/constants) is used to get the `projectId` value from the app config.

</Step>

<Step label="2">

## Add a minimal working example

The code below shows a working example of how to register for, send, and receive push notifications in a React Native app. Copy and paste it into your project:

```tsx App.tsx
import { useState, useEffect, useRef } from 'react';
import { Text, View, Button, Platform } from 'react-native';
import * as Device from 'expo-device';
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';

/* @info This handler determines how your app handles notifications that come in while the app is foregrounded. */
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});
/* @end */

/* @info Sends a notification to Expo. Can also use Expo's push notification tool at https://expo.dev/notifications. */
async function sendPushNotification(expoPushToken: string) {
  const message = {
    to: expoPushToken,
    sound: 'default',
    title: 'Original Title',
    body: 'And here is the body!',
    data: { someData: 'goes here' },
  };

  await fetch('https://exp.host/--/api/v2/push/send', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Accept-encoding': 'gzip, deflate',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(message),
  });
}
/* @end */

function handleRegistrationError(errorMessage: string) {
  alert(errorMessage);
  throw new Error(errorMessage);
}

async function registerForPushNotificationsAsync() {
  if (Platform.OS === 'android') {
    Notifications.setNotificationChannelAsync('default', {
      name: 'default',
      importance: Notifications.AndroidImportance.MAX,
      vibrationPattern: [0, 250, 250, 250],
      lightColor: '#FF231F7C',
    });
  }

  if (Device.isDevice) {
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    if (finalStatus !== 'granted') {
      handleRegistrationError('Permission not granted to get push token for push notification!');
      return;
    }
    const projectId =
      Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
    if (!projectId) {
      handleRegistrationError('Project ID not found');
    }
    try {
      /* @info This fetches the Expo push token (if not previously fetched), which is unique to this device and projectID. */
      const pushTokenString = (
        await Notifications.getExpoPushTokenAsync({
          projectId,
        })
      ).data;
      /* @end */
      console.log(pushTokenString);
      return pushTokenString;
    } catch (e: unknown) {
      handleRegistrationError(`${e}`);
    }
  } else {
    handleRegistrationError('Must use physical device for push notifications');
  }
}

export default function App() {
  const [expoPushToken, setExpoPushToken] = useState('');
  const [notification, setNotification] = useState<Notifications.Notification | undefined>(
    undefined
  );
  const notificationListener = useRef<Notifications.Subscription>();
  const responseListener = useRef<Notifications.Subscription>();

  useEffect(() => {
    /* @info Gets the push token and displays it in the UI, or in case of an error, displays the error message. */
    registerForPushNotificationsAsync()
      .then(token => setExpoPushToken(token ?? ''))
      .catch((error: any) => setExpoPushToken(`${error}`));
    /* @end */

    notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
      setNotification(notification);
    });

    responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
      console.log(response);
    });

    return () => {
      notificationListener.current &&
        Notifications.removeNotificationSubscription(notificationListener.current);
      responseListener.current &&
        Notifications.removeNotificationSubscription(responseListener.current);
    };
  }, []);

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'space-around' }}>
      <Text>Your Expo push token: {expoPushToken}</Text>
      <View style={{ alignItems: 'center', justifyContent: 'center' }}>
        <Text>Title: {notification && notification.request.content.title} </Text>
        <Text>Body: {notification && notification.request.content.body}</Text>
        <Text>Data: {notification && JSON.stringify(notification.request.content.data)}</Text>
      </View>
      <Button
        title="Press to Send Notification"
        onPress={async () => {
          await sendPushNotification(expoPushToken);
        }}
      />
    </View>
  );
}
```

### Configure `projectId`

Using the previous example, when you are registering for push notifications, you need to use [`projectId`](/versions/latest/sdk/constants/#easconfig). This property is used to attribute Expo push token to the specific project. For projects using EAS, the `projectId` property represents the Universally Unique Identifier (UUID) of that project.

`projectId` is automatically set when you create a development build. However, **we recommend setting it manually in your project's code**. To do so, you can use [`expo-constants`](/versions/latest/sdk/constants/) to get the `projectId` value from the app config.

```js
token = await Notifications.getExpoPushTokenAsync({
  projectId: Constants.expoConfig.extra.eas.projectId,
});
```

One advantage of attributing the Expo push token to your project's ID is that it doesn't change when a project is transferred between different accounts or the existing account gets renamed.

</Step>

<Step label="3">

## Get credentials for development builds

For Android and iOS, there are different requirements to set up your credentials.

<Tabs tabs={["Android", "iOS"]}>
  <Tab>
    For Android, you need to configure **Firebase Cloud Messaging (FCM) V1** to get credentials and set up your Expo project.

    Follow the steps in [Add Android FCM V1 credentials](/push-notifications/fcm-credentials) to set up your credentials.

  </Tab>
  <Tab>
    > **warning** A paid Apple Developer Account is required to generate credentials.

    For iOS, make sure you have [registered your iOS device](/develop/development-builds/create-a-build/#create-a-development-build-for-the-device) on which you want to test before running the `eas build` command for the first time.

    If you create a development build for the first time, you'll be asked to enable push notifications. Answer yes to the following questions when prompted by the EAS CLI:

    - Setup Push Notifications for your project
    - Generating a new Apple Push Notifications service key

  </Tab>
</Tabs>

<br />

> If you are not using EAS Build, run `eas credentials` manually.

</Step>

<Step label="4">
## Test using the push notifications tool

After creating and installing the development build, you can use [Expo's push notifications tool](https://expo.dev/notifications) to quickly send a test notification to your device.

1. Start the development server for your project:

   <Terminal cmd={['$ npx expo start']} />

2. Open the development build on your device.

3. After the `ExpoPushToken` is generated, enter the value in the Expo push notifications tool with other details (for example, a message title and body).

4. Click on the **Send a Notification** button.

   <ContentSpotlight
     alt="Expo push notifications tool overview."
     src="/static/images/notifications/push-notifications-tool-overview.png"
     className="max-w-screen-xl"
   />

After sending the notification from the tool, you should see the notification on your device. Below is an example of an Android device receiving a push notification.

  <ContentSpotlight
    alt="An Android device receiving a push notification."
    src="/static/images/notifications/notification-on-android.png"
    className="max-w-[280px]"
  />
</Step>
